#ifndef _GX_MAP_H_
#define _GX_MAP_H_

#include "misc_map.h"

/* POLYGON_ATTR */

#define REG_G3_POLYGON_ATTR_ID_SHIFT                       24
#define REG_G3_POLYGON_ATTR_ID_SIZE                        6
#define REG_G3_POLYGON_ATTR_ID_MASK                        0x3f000000

#define REG_G3_POLYGON_ATTR_ALPHA_SHIFT                    16
#define REG_G3_POLYGON_ATTR_ALPHA_SIZE                     5
#define REG_G3_POLYGON_ATTR_ALPHA_MASK                     0x001f0000

#define REG_G3_POLYGON_ATTR_FE_SHIFT                       15
#define REG_G3_POLYGON_ATTR_FE_SIZE                        1
#define REG_G3_POLYGON_ATTR_FE_MASK                        0x00008000

#define REG_G3_POLYGON_ATTR_DT_SHIFT                       14
#define REG_G3_POLYGON_ATTR_DT_SIZE                        1
#define REG_G3_POLYGON_ATTR_DT_MASK                        0x00004000

#define REG_G3_POLYGON_ATTR_D1_SHIFT                       13
#define REG_G3_POLYGON_ATTR_D1_SIZE                        1
#define REG_G3_POLYGON_ATTR_D1_MASK                        0x00002000

#define REG_G3_POLYGON_ATTR_FC_SHIFT                       12
#define REG_G3_POLYGON_ATTR_FC_SIZE                        1
#define REG_G3_POLYGON_ATTR_FC_MASK                        0x00001000

#define REG_G3_POLYGON_ATTR_XL_SHIFT                       11
#define REG_G3_POLYGON_ATTR_XL_SIZE                        1
#define REG_G3_POLYGON_ATTR_XL_MASK                        0x00000800

#define REG_G3_POLYGON_ATTR_FR_SHIFT                       7
#define REG_G3_POLYGON_ATTR_FR_SIZE                        1
#define REG_G3_POLYGON_ATTR_FR_MASK                        0x00000080

#define REG_G3_POLYGON_ATTR_BK_SHIFT                       6
#define REG_G3_POLYGON_ATTR_BK_SIZE                        1
#define REG_G3_POLYGON_ATTR_BK_MASK                        0x00000040

#define REG_G3_POLYGON_ATTR_PM_SHIFT                       4
#define REG_G3_POLYGON_ATTR_PM_SIZE                        2
#define REG_G3_POLYGON_ATTR_PM_MASK                        0x00000030

#define REG_G3_POLYGON_ATTR_LE_SHIFT                       0
#define REG_G3_POLYGON_ATTR_LE_SIZE                        4
#define REG_G3_POLYGON_ATTR_LE_MASK                        0x0000000f 

// x1B5G5R5 format
typedef u16 GXRgb;
#define GXRGB_ASSERT(gxrgb)       SDK_ASSERT(((gxrgb) & 0x8000) == 0)
#define GX_RGB_R_SHIFT            (0)
#define GX_RGB_R_MASK             (0x001f)
#define GX_RGB_G_SHIFT            (5)
#define GX_RGB_G_MASK             (0x03e0)
#define GX_RGB_B_SHIFT            (10)
#define GX_RGB_B_MASK             (0x7c00)
#define GX_RGB(r, g, b)           ((GXRgb)(((r) << GX_RGB_R_SHIFT) | \
                                           ((g) << GX_RGB_G_SHIFT) | \
                                           ((b) << GX_RGB_B_SHIFT)))

typedef enum
{
    GX_LIGHTMASK_NONE = 0,
    GX_LIGHTMASK_0 = 1,
    GX_LIGHTMASK_1 = 2,
    GX_LIGHTMASK_01 = 3,
    GX_LIGHTMASK_2 = 4,
    GX_LIGHTMASK_02 = 5,
    GX_LIGHTMASK_12 = 6,
    GX_LIGHTMASK_012 = 7,
    GX_LIGHTMASK_3 = 8,
    GX_LIGHTMASK_03 = 9,
    GX_LIGHTMASK_13 = 10,
    GX_LIGHTMASK_013 = 11,
    GX_LIGHTMASK_23 = 12,
    GX_LIGHTMASK_023 = 13,
    GX_LIGHTMASK_123 = 14,
    GX_LIGHTMASK_0123 = 15
}
GXLightMask;

typedef enum
{
    GX_LIGHTID_0 = 0,
    GX_LIGHTID_1 = 1,
    GX_LIGHTID_2 = 2,
    GX_LIGHTID_3 = 3
}
GXLightId;

typedef enum
{
    GX_BEGIN_TRIANGLES = 0,
    GX_BEGIN_QUADS = 1,
    GX_BEGIN_TRIANGLE_STRIP = 2,
    GX_BEGIN_QUAD_STRIP = 3
}
GXBegin;

typedef enum
{
    GX_POLYGONMODE_MODULATE = 0,
    GX_POLYGONMODE_DECAL = 1,
    GX_POLYGONMODE_TOON = 2,
    GX_POLYGONMODE_SHADOW = 3
}
GXPolygonMode;

typedef enum
{
    GX_CULL_ALL = 0,
    GX_CULL_FRONT = 1,
    GX_CULL_BACK = 2,
    GX_CULL_NONE = 3
}
GXCull;

typedef enum
{
    GX_POLYGON_ATTR_MISC_NONE = 0,
    GX_POLYGON_ATTR_MISC_XLU_DEPTH_UPDATE = 1 << REG_G3_POLYGON_ATTR_XL_SHIFT,
    GX_POLYGON_ATTR_MISC_FAR_CLIPPING = 1 << REG_G3_POLYGON_ATTR_FC_SHIFT,
    GX_POLYGON_ATTR_MISC_DISP_1DOT = 1 << REG_G3_POLYGON_ATTR_D1_SHIFT,
    GX_POLYGON_ATTR_MISC_DEPTHTEST_DECAL = 1 << REG_G3_POLYGON_ATTR_DT_SHIFT,
    GX_POLYGON_ATTR_MISC_FOG = 1 << REG_G3_POLYGON_ATTR_FE_SHIFT
}
GXPolygonAttrMisc;

typedef enum
{
    GX_MTXMODE_PROJECTION = 0,
    GX_MTXMODE_POSITION = 1,
    GX_MTXMODE_POSITION_VECTOR = 2,
    GX_MTXMODE_TEXTURE = 3
}
GXMtxMode;

typedef enum
{
    GX_TEXFMT_NONE = 0,
    GX_TEXFMT_A3I5 = 1,
    GX_TEXFMT_PLTT4 = 2,
    GX_TEXFMT_PLTT16 = 3,
    GX_TEXFMT_PLTT256 = 4,
    GX_TEXFMT_COMP4x4 = 5,
    GX_TEXFMT_A5I3 = 6,
    GX_TEXFMT_DIRECT = 7
}
GXTexFmt;

#define GX_TEXFMT_ALPHA ((GXTexFmt)GX_TEXFMT_A5I3) // Obsolete name

typedef enum
{
    GX_TEXGEN_NONE = 0,
    GX_TEXGEN_TEXCOORD = 1,
    GX_TEXGEN_NORMAL = 2,
    GX_TEXGEN_VERTEX = 3
}
GXTexGen;

typedef enum
{
    GX_TEXSIZE_S8 = 0,
    GX_TEXSIZE_S16 = 1,
    GX_TEXSIZE_S32 = 2,
    GX_TEXSIZE_S64 = 3,
    GX_TEXSIZE_S128 = 4,
    GX_TEXSIZE_S256 = 5,
    GX_TEXSIZE_S512 = 6,
    GX_TEXSIZE_S1024 = 7
}
GXTexSizeS;

typedef enum
{
    GX_TEXSIZE_T8 = 0,
    GX_TEXSIZE_T16 = 1,
    GX_TEXSIZE_T32 = 2,
    GX_TEXSIZE_T64 = 3,
    GX_TEXSIZE_T128 = 4,
    GX_TEXSIZE_T256 = 5,
    GX_TEXSIZE_T512 = 6,
    GX_TEXSIZE_T1024 = 7
}
GXTexSizeT;

typedef enum
{
    GX_TEXREPEAT_NONE = 0,
    GX_TEXREPEAT_S = 1,
    GX_TEXREPEAT_T = 2,
    GX_TEXREPEAT_ST = 3
}
GXTexRepeat;

typedef enum
{
    GX_TEXFLIP_NONE = 0,
    GX_TEXFLIP_S = 1,
    GX_TEXFLIP_T = 2,
    GX_TEXFLIP_ST = 3
}
GXTexFlip;

typedef enum
{
    GX_TEXPLTTCOLOR0_USE = 0,
    GX_TEXPLTTCOLOR0_TRNS = 1
}
GXTexPlttColor0;

typedef enum
{
    GX_SHADING_TOON = 0,
    GX_SHADING_HIGHLIGHT = 1
}
GXShading;

typedef enum
{
    GX_BLEND_PLANEMASK_NONE = 0x0000,
    GX_BLEND_PLANEMASK_BG0 = 0x0001,
    GX_BLEND_PLANEMASK_BG1 = 0x0002,
    GX_BLEND_PLANEMASK_BG2 = 0x0004,
    GX_BLEND_PLANEMASK_BG3 = 0x0008,
    GX_BLEND_PLANEMASK_OBJ = 0x0010,
    GX_BLEND_PLANEMASK_BD = 0x0020
}
GXBlendPlaneMask;

void GX_VBlankIntr(bool test);

void G3_Begin(GXBegin primitive);
void G3_End();

void G3_TexCoord(fx32 s, fx32 t);
void G3_Normal(fx16 x, fx16 y, fx16 z);
void G3_Vtx(fx16 x, fx16 y, fx16 z);

void G3_PolygonAttr(int light,GXPolygonMode polyMode,GXCull cullMode,int polygonID,int alpha,int misc);
void G3_LightVector(GXLightId lightID, fx16 x, fx16 y, fx16 z);
void G3_LightColor(GXLightId lightID, GXRgb rgb);

void G3_MaterialColorDiffAmb(GXRgb diffuse, GXRgb ambient, BOOL IsSetVtxColor);
void G3_MaterialColorSpecEmi(GXRgb specular, GXRgb emission, BOOL IsShininess);

void G3_LookAt(const VecFx32 * camPos,const VecFx32 * camUp,const VecFx32 * target,MtxFx43 * mtx);

void G3_MtxMode(GXMtxMode mode);

void G3_Identity();
void G3_Scale(fx32 x, fx32 y, fx32 z);
void G3_Translate(fx32 x, fx32 y, fx32 z);

void GX_BeginLoadTex(void);
void GX_LoadTex(const void *pSrc, u32 destSlotAddr, u32 szByte);
void GX_EndLoadTex(void);
void GX_BeginLoadTexPltt(void);
void GX_LoadTexPltt(const void *pSrc, u32 destSlotAddr, u32 szByte);
void GX_EndLoadTexPltt(void);

void G3_TexImageParam(GXTexFmt texFmt,GXTexGen texGen,GXTexSizeS s,GXTexSizeT t,GXTexRepeat repeat,GXTexFlip flip,GXTexPlttColor0 pltt0,u32 addr);
void G3_TexPlttBase(u32 addr, GXTexFmt texFmt);

void G3X_Reset();
void G3_PushMtx();
void G3_PopMtx(int num);

void G3_RotX(fx32 s, fx32 c);
void G3_RotY(fx32 s, fx32 c);
void G3_RotZ(fx32 s, fx32 c);

void G3X_SetShading(GXShading shading);

void G3X_AntiAlias(BOOL enable);
void G3X_AlphaBlend(BOOL enable);
void G2_SetBlendAlpha(int plane1,int plane2,int ev1,int ev2);

#endif